The Bollinger Strategy

The strategy buys \(1\) share if the stock is cheap (the z-score is less than minus the threshold), and it sells \(1\) share if the stock is expensive (the z-score is greater than the threshold).

The strategy can sell shares short (establish a short share position), if it doesn’t own any shares to sell.

The strategy keeps buying or selling shares, and can accumulate an inventory of long or short shares, until it reaches the position limit.

The strategy determines if the stock is cheap or expensive depending on the value of the z-score.

The z-score \(z_t\) is equal to the difference between the current price \(p_t\) minus the moving average price \(\bar{p}_t\), divided by the moving average volatility of the prices \(\sigma_t\):

\[{\normalsize z_t = \frac{p_t - \bar{p}_t}{\sigma_t}}\]

If the current price \(p_t\) is greater than the moving average price \(\bar{p}_t\), then the z-score is positive, and vice versa.

You can read more about the implementation of the Bollinger Strategy

Click to Read

Click to Download

download here


The Moving Average Prices

The moving average prices can be calculated for a streaming time series of prices \(p_t\).

The Exponential Moving Average (EMA) price \(\bar{p}_t\) is calculated using a decay factor \(\lambda\) and the recursive formula:

\[{\normalsize \bar{p}_t = \lambda \bar{p}_{t-1} + (1-\lambda) p_t}\]

The moving average price at time \(t\): \(p_t\) is equal to the decay factor \(\lambda\) times the moving average price at time \(t-1\): \(p_{t-1}\), plus \((1-\lambda)\) times the price at time \(t-1\): \(\bar{p}_{t-1}\).

The decay factor \(\lambda\) determines the persistence of data memory, i.e. how quickly the contribution of the past data to the average value fades over time.

If the decay factor \(\lambda\) is closer to \(1\) then the effect of past data fades slowly over time. If \(\lambda\) is closer to \(0\) then the effect of past data fades quickly over time.

The above recursive formula can be expressed as a series:

\[{\normalsize \bar{p}_t = (1-\lambda) \sum\limits_{j=0}^{\infty} {\lambda}^j p_{t-j} = (1-\lambda) (p_t + \lambda p_{t-1} + \lambda^2 p_{t-2} + \ldots)} \]

The formula is called exponential because the decay factor \(\lambda\) is raised to the power of \(j\), so the weights \(\lambda^j\) decrease exponentially as \(j\) increases.

The advantage of the EMA price is that it applies a greater weight to more recent prices than to past ones.

The EMA calculation is also faster because there’s less computation, and it doesn’t require maintaining a buffer (queue) of past prices.


The Moving Average Variance of Prices

The moving average variance of prices \(\sigma^2_t\) measures the dispersion of the streaming prices around the moving average price. It can be calculated for a streaming time series of prices \(p_t\).

The Exponential Moving Average (EMA) variance of prices \(\sigma^2_t\) is calculated using the two recursive formulas:

\[{\normalsize \sigma^2_t = \lambda \sigma^2_{t-1} + (1-\lambda) (p_t - \bar{p}_{t-1})^2}\] \[{\normalsize \bar{p}_t = \lambda \bar{p}_{t-1} + (1-\lambda) p_t}\]

The moving average variance at time \(t\): \(\sigma^2_t\) is equal to the decay factor \(\lambda\) times the moving average variance at time \(t-1\): \(\sigma^2_{t-1}\), plus \((1-\lambda)\) times the squared difference between the current price \(p_t\) minus the moving average price at time \(t-1\): \(\bar{p}_{t-1}\).


Choosing The Decay Factor \(\lambda\)

The moving average prices are a smoothed version of the streaming prices.

The decay factor \(\lambda\) determines the strength of the data smoothing.

If \(\lambda\) is closer to \(1\) then the moving average prices are smoother, but if it’s closer to \(0\) then the average prices are more variable and they follow the streaming prices more closely.

The effect of the decay factor \(\lambda\) on the moving average prices is illustrated in the animated plot below of VTI stock prices. When \(\lambda = 0.99\) the average prices are very smooth, but as it decreases, they become more variable and they follow the streaming prices more closely.


The moving average prices are less volatile (smoother), but they also lag behind the streaming prices - they are biased.
Notice for example that the average prices (red line above) reach their minimum much later than the streaming prices (blue line).
And the smoother the average prices are, the more biased they are.
A lower variance is desirable, but it comes at the cost of a larger bias (time lag).
This is called the bias-variance tradeoff.
The bias-variance tradeoff is one of the central themes in machine learning.

The decay factor \(\lambda\) and the look-back window \(lb\) are usually chosen to achieve the best bias-variance tradeoff.

The best tradeoff depends on the application. For example, if the streaming prices are very volatile, then a larger decay factor \(\lambda\) is desirable (or a larger look-back window \(lb\)), to reduce the volatility.

The optimal value of the decay factor \(\lambda\) can be determined using a simulation called backtesting (cross-validation).

Backtesting is performed on historical data.
The data is split into in-sample and out-of-sample sets.
Forecasting models often require the smoothing of the data.
The smoothing is applied to the in-sample data, and the forecasts are tested on the out-of-sample data.
The value of \(\lambda\) which minimizes the out-of-sample forecast errors is chosen as the optimal value.

The backtesting procedure risks overfitting to the historical data.
The optimal value of \(\lambda\) may not be the best choice in live data. So users should be cautious when selecting parameters using the backtesting procedure.